library(httr)
library(jsonlite)
library(tidyverse)
getCarpobrotusObservations <- function(place_id, taxon_id, quality_grade){
total_results = NULL
page = 1
delay = 1.0
results = tibble()
while(is.null(total_results) || nrow(results) < total_results) {
call_url <- str_glue('https://api.inaturalist.org/v1/observations?',
'place_id={place_id}&taxon_id={taxon_id}',
'&captive=false&geoprivacy=open',
'&quality_grade={quality_grade}',
'&per_page=200&page={page}')
get_json_call <- GET(url = call_url) %>%
content(as = "text") %>% fromJSON(flatten = TRUE)
if (!is.null(get_json_call)) {
if (is.null(total_results)) {
total_results <- get_json_call$total_results # number of results of the call
}
results_i <- as_tibble(get_json_call$results) %>%
select(taxon.name, taxon.rank, identifications_count,
created_at, observed_on,
geojson.coordinates, positional_accuracy,
user.login, user.id, user.name, user.observations_count,
user.identifications_count, user.activity_count,
license_code, num_identification_agreements, uri) %>%
unnest_wider(geojson.coordinates, names_sep = "_") %>%
rename(longitude=geojson.coordinates_1, latitude=geojson.coordinates_2)
results <- rbind(results, results_i)
page <- page + 1
Sys.sleep(delay)
}
}
return(results)
}
datos_carpobrotus <- getCarpobrotusObservations(place_id=7259,
taxon_id=49322,
quality_grade='research')
datos_carpobrotus <- datos_carpobrotus %>% filter(created_at<='2023-06-09')Datos de Carpobrotus edulis en NaturalistaUY
Descarga de datos de Carpobrotus edulis
Para descargar datos de NaturalistaUY usé la API de iNaturalist. Los datos se descargan considerando:
- Uruguay como localización:
place_id=7259 - Carpobrotus edulis como taxón:
taxon_id=49322 - Registros con Grado de Investigación:
quality_grade=research
9 de junio, 2023
Análisis espacial y temporal
Resumen de los datos de Carpobrotus edulis disponibles.
Distribución espacial
Para descargar los mapas usé el paquete geouy, haciendo: geouy::load_geouy('Dptos'). Guardé este objeto para evitar descargarlo nuevamente. El archivo tiene como CRS EPSG:32721.
Code
library(lubridate)
library(geonames)
options(geonamesUsername="biodiversidata") # A (free) username is required and rate limits exist
library(tmap)
tmap_mode("view")
library(sf)
sf::sf_use_s2(FALSE)
# options
options(scipen = 999)
uruguay <- readRDS('data/Uruguay.rds')
deptos_costeros <- c('MONTEVIDEO','MALDONADO','CANELONES', 'ROCHA')
costa_uruguay <- uruguay %>% filter(nombre %in% deptos_costeros)
getStateProvince <- function(lat, lng){
subdivision <- try(GNcountrySubdivision(lat, lng, radius = "1", maxRows = 1), silent = TRUE)
Sys.sleep(1.0)
if(class(subdivision)=='try-error'){
subdivision$adminName1 <- NA
}
else if (length(subdivision$adminName1)==0){
subdivision$adminName1 <- NA
}
return(subdivision$adminName1)
}
# departamento de registro
datos_carpobrotus<- datos_carpobrotus %>%
mutate(stateProvince=map2_chr(latitude, longitude, getStateProvince))
# estación del año
datos_carpobrotus<- datos_carpobrotus %>%
mutate(observed_on=as_date(observed_on)) %>%
mutate(season=lubridate::quarter(observed_on)) %>%
mutate(season=ifelse(season==1, 'verano',
ifelse(season==2, 'otoño',
ifelse(season==3, 'invierno', 'primavera'))))
saveRDS(datos_carpobrotus, 'data/datos_carpobrotus.rds')
write_excel_csv(datos_carpobrotus, 'data/datos_carpobrotus.csv', na = '')
sf_carpobrotus <- datos_carpobrotus %>%
st_as_sf(coords = c("longitude", "latitude")) %>%
st_set_crs(4326) %>%
st_transform(32721)
mapa.carpobrotus <- tm_graticules(alpha = 0.3) +
tm_shape(costa_uruguay) +
tm_fill(col='grey90') +
tm_borders(col='grey60', alpha = 0.4) +
tm_shape(sf_carpobrotus) +
tm_dots(alpha = 0.4)
mapa.carpobrotusDatos por departamento
Code
library(knitr)
datos_carpobrotus %>%
group_by(stateProvince) %>%
count() %>% rename(Departamento=stateProvince,
`Cantidad de registros`=n) %>%
kable()| Departamento | Cantidad de registros |
|---|---|
| Canelones | 46 |
| Maldonado | 98 |
| Montevideo | 11 |
| Montevideo Department | 1 |
| Rocha | 48 |
Datos en Áreas Protegidas
Code
areas_protegidas <- readRDS('data/areas_protegidas.rds')
localidades <- readRDS('data/localidades.rds')
AP_en_la_costa <- st_intersection(areas_protegidas, costa_uruguay) %>% st_drop_geometry %>% select(nombre) %>% pull
areas_protegidas <- areas_protegidas %>%
filter(nombre %in% AP_en_la_costa)
carpobrotus_areas_protegidas <- st_join(areas_protegidas,
sf_carpobrotus) %>%
group_by(id, nombre) %>%
summarise(NR=ifelse(n_distinct(taxon.name, na.rm=T)!=0, n(), 0),
presence=ifelse(NR>0, 1, 0)) %>%
st_cast()
mapa.carpobrotus.areas_protegidas <- tm_graticules(alpha = 0.3) +
tm_shape(costa_uruguay) +
tm_fill(col='grey90') +
tm_borders(col='grey60', alpha = 0.4) +
tm_shape(carpobrotus_areas_protegidas) +
tm_fill('presence', alpha = 0.4, style = 'cat', palette = 'Set1')
mapa.carpobrotus.areas_protegidasCobertura temporal
Un total de 78 usuaries tomaron 204 registros de Carpobrotus edulis. El primer registro es de 2008-03-16 y el último es de 2023-05-10.
- Estacionalidad
Code
library(patchwork)
timeline.plot <- datos_carpobrotus %>%
add_count(taxon.name, year=year(observed_on),
name='records_per_year') %>%
ggplot(., aes(x=observed_on, y=records_per_year)) +
geom_line(show.legend = FALSE, size=1) +
scale_x_date(date_breaks = "1 year", date_labels = "%Y") +
theme_bw()+
labs(x='', y= 'Número de registros por año')
timeline.plot <- datos_carpobrotus %>%
add_count(taxon.name, year=year(observed_on),
name='records_per_year') %>%
ggplot(., aes(x=observed_on, y=records_per_year)) +
geom_line(show.legend = FALSE, size=1) +
scale_x_date(date_breaks = "1 year", date_labels = "%Y") +
theme_bw()+
labs(x='', y= 'Number of records per year')
season.year.plot <- datos_carpobrotus %>%
add_count(taxon.name, season, name='records_per_season') %>%
mutate(season=factor(season,
levels = c('verano', 'otoño', 'invierno', 'primavera'))) %>%
ggplot(aes(x=season, y=observed_on)) +
geom_jitter(aes(col = season), width = 0.01, show.legend = FALSE) +
stat_summary(fun = mean, fun.min = min, fun.max = max) +
theme_bw() +
labs(x='', y= 'Fecha')
season.n.plot <- datos_carpobrotus %>%
add_count(taxon.name, season, name='records_per_season') %>%
mutate(season=factor(season,
levels = c('verano', 'otoño', 'invierno', 'primavera'))) %>%
ggplot(aes(x=season, y=records_per_season)) +
geom_segment(aes(x=season, xend=season, y=0,
yend=records_per_season, col=season), show.legend = FALSE) +
geom_point(aes(col=season), show.legend = FALSE) +
theme_bw() +
labs(x='', y= 'Número de registros')
timeline.plot / (season.year.plot | season.n.plot)Code
ggsave(plot = timeline.plot, filename='figs/timeline.plot.svg', device = 'svg', width=6, height=3, dpi=300)Análisis de las fotografías de Carpobrotus edulis
- Densidad: high, medium, low
- Fenología: no evidence of flowering/fruiting, flowering, flower budding , fruiting, flowering/flower budding, flowering/fruiting
- Presencia de infraestructura humana: present, absent
Code
photo_evaluation <- read_csv('data/photo_evalutaion.csv')
photo_evaluation_carpobrotus <- left_join(datos_carpobrotus,
photo_evaluation %>% select(uri, density, phenology, infrastructure)) %>%
mutate(density = case_when(density=='alta'|density=='alta/media' ~ 'high',
density=='media'|density=='media/alta' ~ 'medium',
density=='baja' ~ 'low')) %>%
mutate(phenology=ifelse(phenology=='No evidence of flowering', 'no evidence of flowering/fruiting', phenology)) %>%
mutate(infrastructure = case_when(infrastructure==0 ~ 'absent',
infrastructure==1 ~ 'present',
is.na(infrastructure) ~ 'not assessed'))
photo_evaluation_carpobrotus %>%
group_by(density) %>%
summarise(count = n()) %>%
mutate(freq = scales::label_percent()(count / sum(count))) %>%
arrange(desc(count)) %>%
rename(Density=density, N=count, `%`=freq) %>%
kable()| Density | N | % |
|---|---|---|
| high | 75 | 36.8% |
| medium | 67 | 32.8% |
| NA | 33 | 16.2% |
| low | 29 | 14.2% |
Code
photo_evaluation_carpobrotus %>%
group_by(phenology) %>%
summarise(count = n()) %>%
mutate(freq = scales::label_percent()(count / sum(count))) %>%
arrange(desc(count)) %>%
rename(Phenology=phenology, N=count, `%`=freq) %>%
kable()| Phenology | N | % |
|---|---|---|
| no evidence of flowering/fruiting | 117 | 57.35% |
| fruiting | 42 | 20.59% |
| flowering | 27 | 13.24% |
| flowering/flower budding | 11 | 5.39% |
| flowering/fruiting | 4 | 1.96% |
| flower budding | 3 | 1.47% |
Code
photo_evaluation_carpobrotus %>%
group_by(infrastructure) %>%
summarise(count = n()) %>%
mutate(freq = scales::label_percent()(count / sum(count))) %>%
arrange(desc(count)) %>%
rename(Infrastructure=infrastructure, N=count, `%`=freq) %>%
kable()| Infrastructure | N | % |
|---|---|---|
| absent | 120 | 58.8% |
| present | 46 | 22.5% |
| not assessed | 38 | 18.6% |
Descarga de todos los datos en NaturalistaUY para Montevideo, Canelones, Maldonado y Rocha
Usamos:
- Montevideo, Canelones, Maldonado y Rocha como localización:
place_id=12416,place_id=12410,place_id=12415,place_id=12420 - Que no sean de organismos cultivados/captivos:
captive=false - Que tengan
geoprivacy=open
Estos datos los descargamos directamente de naturalista.uy/observations/export.
9 de junio, 2023
Code
allObservations <- read_csv('data/observations-334644.csv', guess_max = 72000)
allObservations <- allObservations %>%
filter(coordinates_obscured==FALSE &
!is.na(taxon_species_name) &
captive_cultivated == FALSE) %>%
select(kingdom=taxon_kingdom_name, phylum=taxon_phylum_name,
class=taxon_class_name, order=taxon_order_name,
family=taxon_family_name, genus=taxon_genus_name,
species=taxon_species_name, scientific_name,
quality_grade, observed_on, user_login, user_id,
state_province=place_admin1_name,
longitude, latitude)
allObservations_sf <- allObservations %>%
st_as_sf(coords = c("longitude", "latitude")) %>%
st_set_crs(4326) %>%
st_transform(32721)Análisis espacial
- Creación de grillas para los cuatro departamentos de la costa (10x10km)
Code
costa_uruguay_grillas <- st_make_grid(st_union(costa_uruguay), 10000) %>%
st_intersection(st_union(costa_uruguay)) %>%
st_sf(gridID=1:length(.), geometry= .) %>%
st_make_valid() %>% st_cast() Intersección de grillas con datos totales y para Caprobrotus edulis
Code
grillas_allObservations <- st_join(costa_uruguay_grillas,
allObservations_sf) %>%
group_by(gridID) %>%
summarise(NR=ifelse(n_distinct(species, na.rm=T)!=0, n(), 0),
SR=n_distinct(species, na.rm = T),
spsList = paste(species, collapse = ';')) %>%
st_cast()
grillas_carpobrotus <- st_join(costa_uruguay_grillas, sf_carpobrotus) %>%
group_by(gridID) %>%
summarise(NR=ifelse(n_distinct(taxon.name, na.rm=T)!=0, n(), 0)) %>%
st_cast()Estimación del esfuerzo de muestreo por grilla
Usamos la función get_gridsSlopes() generada para análisis de Biodiversidata (Grattarola et al. 2020).
El código está disponible en GitHub: Multiple forms of hotspots of tetrapod biodiversity and the challenges of open-access data scarcity.
To identify the areas of ignorance we quantified the levels of inventory incompleteness for each group by using curvilinearity of smoothed species accumulation curves (SACs). This method assumes that SACs of poorly sampled grids tend towards a straight line, while those of better sampled ones have a higher degree of curvature. As a proxy for inventory incompleteness we calculated the degree of curvilinearity as the mean slope of the last 10% of SACs.
Code
# The function ```get_gridsSlopes``` finds a species accumulation curve (SAC) for each grid-cell using the method ‘exact’ of the function ```specaccum``` of the vegan package and then calculates the degree of curvilinearity as the mean slope of the last 10% of the curve.
library(vegan)
library(spaa)
get_gridsSlopes <- function(data_abundance){
gridSlope <- data.frame(gridID=integer(), slope=numeric(), stringsAsFactors=FALSE)
data_abundance <- as.data.frame(data_abundance)
data_abundance$abundance <- as.integer(1)
cells <- unique(data_abundance$gridID)
splistT <- list()
spaccum <- list()
slope <- list()
for (i in cells) {
splist <- data_abundance[data_abundance$gridID == i,c(2:4)]
splistT[[i]] = data2mat(splist)
spaccum[[i]] = specaccum(splistT[[i]], method = "exact")
slope[[i]] = (spaccum[[i]][[4]][length(spaccum[[i]][[4]])]-
spaccum[[i]][[4]][ceiling(length(spaccum[[i]][[4]])*0.9)])/
(length(spaccum[[i]][[4]])- ceiling(length(spaccum[[i]][[4]])*0.9))
gridSlope_i <- data.frame(gridID=i, slope=slope[[i]], stringsAsFactors=FALSE)
gridSlope <- rbind(gridSlope, gridSlope_i)
}
gridSlope <- gridSlope %>% as_tibble() %>%
mutate(slope=ifelse(is.nan(slope), NA, slope))
return(gridSlope)
}
allObservations.SACs <- grillas_allObservations %>% as_tibble() %>%
mutate(species=str_split(spsList, ';')) %>%
unnest(species) %>%
group_by(spsList) %>% mutate(sample = row_number()) %>%
ungroup() %>%
mutate(sample=ifelse(is.na(species), 0 , sample)) %>%
select(gridID, sample, species)
allObservations.incompleteness <- get_gridsSlopes(allObservations.SACs)Unión espacial de todas los datos por grilla: número de registros totales, número de especies totales, curva de incompleteness (esfuerzo de muestreo), y número de registros de Carpobrotus edulis.
Code
costa_uruguay.incompleteness <- left_join(grillas_allObservations,
allObservations.incompleteness) %>%
left_join(., grillas_carpobrotus %>%
rename(carpobrotus=NR) %>%
st_drop_geometry())Sesgos de muestreo
Mapas
Code
registros.carpobrotus <- ggplot() +
geom_sf(data=costa_uruguay.incompleteness %>%
mutate(carpobrotus=ifelse(carpobrotus==0, NA, carpobrotus)),
aes(fill=carpobrotus)) +
scale_fill_fermenter(palette ='YlGn', direction = 1,
#breaks = c(0,1, 5,10,15,20,25),
na.value="#ede8e8") +
geom_sf(data=costa_uruguay, fill=NA) +
labs(fill='Number of\nCarpobrotus records') +
theme_bw()
n.registros <- ggplot() +
geom_sf(data=costa_uruguay.incompleteness %>%
mutate(NR=ifelse(NR==0, NA, NR)),
aes(fill=NR)) +
scale_fill_fermenter(palette ='YlGn',
direction = 1,
#breaks = c(0, 100, 500, 750, 1000, 1500),
na.value="#ede8e8") +
geom_sf(data=costa_uruguay, fill=NA) +
labs(fill='Total\nnumber of\nrecords') +
theme_bw()
sac <- ggplot() +
geom_sf(data=costa_uruguay.incompleteness, aes(fill=slope)) +
scale_fill_fermenter(palette ='Spectral',
breaks = c(0.1, 0.25, 0.5, 0.75, 0.9, 1),
na.value="#ede8e8") +
geom_sf(data=costa_uruguay, fill=NA) +
labs(fill='Incompleteness') +
theme_bw()
n.registros / registros.carpobrotus / sacCode
# interactivos
tm_graticules(alpha = 0.3) +
tm_shape(costa_uruguay) +
tm_fill(col='grey90') +
tm_borders(col='grey60', alpha = 0.4) +
tm_shape(costa_uruguay.incompleteness %>% select(grilla=gridID, NR, SR, carpobrotus, slope)) +
tm_fill(col = 'slope', palette = 'Spectral', n = 6, style='jenks') Code
tm_graticules(alpha = 0.3) +
tm_shape(costa_uruguay) +
tm_fill(col='grey90') +
tm_borders(col='grey60', alpha = 0.4) +
tm_shape(costa_uruguay.incompleteness %>% select(grilla=gridID, NR, SR, carpobrotus, slope)) +
tm_fill(col = 'carpobrotus', palette = 'Greens', n = 6, style='jenks') Correlaciones
Code
library(ggpubr)
tabla.final <- costa_uruguay.incompleteness %>%
st_drop_geometry() %>%
select(grilla=gridID, NR, SR, carpobrotus, slope)
summary(lm(carpobrotus ~ NR, data=tabla.final))
Call:
lm(formula = carpobrotus ~ NR, data = tabla.final)
Residuals:
Min 1Q Median 3Q Max
-13.3254 -0.1541 0.0797 0.1381 23.3044
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -0.1381389 0.1583721 -0.872 0.384
NR 0.0073048 0.0005093 14.342 <0.0000000000000002 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 2.365 on 259 degrees of freedom
Multiple R-squared: 0.4426, Adjusted R-squared: 0.4405
F-statistic: 205.7 on 1 and 259 DF, p-value: < 0.00000000000000022
Code
nr.caprobrotus <- tabla.final %>% filter(carpobrotus>0) %>%
ggplot(aes(x=NR, y=carpobrotus)) +
geom_jitter() +
geom_smooth(method = 'lm') +
stat_regline_equation(label.y = 30, aes(label = ..eq.label..)) +
stat_regline_equation(label.y = 28, aes(label = ..adj.rr.label..)) +
labs(x='Number of records per grid cell', y='Caprobrotus edulis records per grid cell') +
theme_bw()
summary(lm(carpobrotus ~ slope, data=tabla.final))
Call:
lm(formula = carpobrotus ~ slope, data = tabla.final)
Residuals:
Min 1Q Median 3Q Max
-5.5117 -1.6170 -0.3330 0.8455 29.9189
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 7.202 1.004 7.172 0.000000000044 ***
slope -8.586 1.404 -6.118 0.000000009632 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 3.788 on 135 degrees of freedom
(124 observations deleted due to missingness)
Multiple R-squared: 0.2171, Adjusted R-squared: 0.2113
F-statistic: 37.43 on 1 and 135 DF, p-value: 0.000000009632
Code
incompleteness.caprobrotus <- tabla.final %>% filter(carpobrotus>0) %>%
ggplot(aes(x=slope, y=carpobrotus)) +
geom_point() + geom_smooth(method = 'lm') +
stat_regline_equation(label.y = 30, label.x = 0.65, aes(label = ..eq.label..)) +
stat_regline_equation(label.y = 28, label.x = 0.65, aes(label = ..adj.rr.label..)) +
labs(x='Sampling incompleteness per grid cell', y='Caprobrotus edulis records per grid cell') +
theme_bw()
nr.caprobrotus / incompleteness.caprobrotusTabla final
La tabla final de datos con información por grilla:
- Núm de registros totales: cantidad de registros en NaturalistaUY de cualquier especie
- Núm de especies totales: cantidad de especies en NaturalistaUY
- Núm de registros Carpobrotus: cantidad de registros en NaturalistaUY de Carpobrotus edulis
- Incompleteness: medida de esfuerzo de muestreo (valores cercanos a 0 indican grillas completas)
Code
tabla.final %>% filter(carpobrotus>0) %>% arrange(slope) %>%
select(`Núm de registros totales`=NR,
`Núm de especies`=SR,
`Núm de registros Carpobrotus`=carpobrotus,
Incompleteness=slope) %>%
kable(digits = 3)| Núm de registros totales | Núm de especies | Núm de registros Carpobrotus | Incompleteness |
|---|---|---|---|
| 1980 | 792 | 1 | 0.204 |
| 1507 | 620 | 2 | 0.219 |
| 992 | 424 | 10 | 0.246 |
| 1620 | 691 | 35 | 0.247 |
| 1093 | 493 | 13 | 0.267 |
| 1213 | 572 | 8 | 0.274 |
| 1040 | 493 | 14 | 0.289 |
| 1066 | 508 | 13 | 0.293 |
| 996 | 541 | 7 | 0.312 |
| 1297 | 681 | 4 | 0.335 |
| 635 | 345 | 3 | 0.345 |
| 480 | 250 | 1 | 0.355 |
| 1001 | 568 | 11 | 0.370 |
| 735 | 433 | 19 | 0.393 |
| 443 | 258 | 6 | 0.400 |
| 347 | 205 | 4 | 0.410 |
| 481 | 304 | 8 | 0.453 |
| 326 | 216 | 1 | 0.461 |
| 419 | 267 | 8 | 0.461 |
| 202 | 130 | 1 | 0.462 |
| 122 | 82 | 4 | 0.471 |
| 547 | 365 | 3 | 0.481 |
| 254 | 184 | 4 | 0.566 |
| 239 | 179 | 4 | 0.604 |
| 159 | 122 | 2 | 0.615 |
| 103 | 85 | 3 | 0.698 |
| 89 | 80 | 1 | 0.815 |